package com.bonshotels.DomainLayer.DomainControllers;

import java.util.Date;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;

import com.bonshotels.DomainLayer.CtrlDades.FactoriaCtrlDades;
import com.bonshotels.DomainLayer.CtrlDades.ICtrlPoblacio;
import com.bonshotels.DomainLayer.CtrlDades.IFactoriaCtrlDades;
import com.bonshotels.DomainLayer.DomainModel.Poblacio;
import com.bonshotels.Excepcions.HotelsNoDisp;
import com.bonshotels.Excepcions.NoHiHaPoblacions;
import com.bonshotels.Excepcions.PoblacioNoExisteix;

/**
 * La CUBuscarHabitacio implementa el patro controlador en la seva variant cas d'us.
 * @author Marc Mauri Alloza
 */
public class CUBuscarHabitacio {

	/**
	 * Obte totes les poblacions existents al sistema.
	 * La FactoriaCtrlDades es una classe que implementa el patro ConcreteFactory
	 * i retorna una classe
	 * (definida al paquet DataLayer) que implementa la interficie
	 * ICtrl"NomDeLaClasse" (definida al paquet DomainLayer), d'aquesta manera aconseguim que la
	 * capa de dades depengui de la de domini i no al reves i trenquem una dependencia circular
	 * entre paquets que podria apareixer si DomainLayer depen de DataLayer per ontenir dades de
	 * capa de dades pero DataLayer depen de DomainLayer per construir els objectes de DataLayer 
	 * a partir de les dades que ha obtingut de la BD, i retornar-los a DataLayer. 
	 * 
	 *
	 * @return Un conjunt amb poblacions existents al sistema.
	 * @throws NoHiHaPoblacions 
	 */
	Set<String> obtePoblacions() throws NoHiHaPoblacions {
		IFactoriaCtrlDades fCD = FactoriaCtrlDades.obteInstancia();
		ICtrlPoblacio cP = fCD.obteCtrlPoblacio();
		Set<Poblacio> pobs = cP.obteTots();
		
		if(pobs.isEmpty()) throw new NoHiHaPoblacions();
		Set<String> noms = new HashSet<String>();
		for (Poblacio p : pobs) {
			String pob = p.obteNom();
			noms.add(pob);	
		}
		return noms;		
	}
	
	/**
	 * Busca els hotels de la poblacio que tenen habitacions disponibles en el periode indicat i
	 * pel nombre d'ocupants. Per a cada hotel es mostra el seu nom, la seva descripcio i
	 * categoria, la mitjana de les avaluacions dels seus comentaris i els tipus, el nombre
	 * d'habitacions i el preu (depenent de la promocio que s'hagi aplicat) dels tipus
	 * d'habitacions que te disponibles.
	 * La FactoriaCtrlDades es una classe que implementa el patro ConcreteFactory
	 * i retorna una classe
	 * (definida al paquet DataLayer) que implementa la interficie
	 * ICtrl"NomDeLaClasse" (definida al paquet DomainLayer), d'aquesta manera aconseguim que la
	 * capa de dades depengui de la de domini i no al reves i trenquem una dependencia circular
	 * entre paquets que podria apareixer si DomainLayer depen de DataLayer per ontenir dades de
	 * capa de dades pero DataLayer depen de DomainLayer per construir els objectes de DataLayer 
	 * a partir de les dades que ha obtingut de la BD, i retornar-los a DataLayer. 
	 * 
	 *
	 * @param pob Poblacio on volem buscar els hotels.
	 * @param dIni Data d'inici del periode on volem buscar els hotels.
	 * @param dFi Data de fi del periode on volem buscar els hotels.
	 * @param numOcup Numero d'ocupants que ocuparan l'habitacio.
	 * @return Un Set amb un Map amb el nom de l'hotel (key: "nomHotel"), la descripcio (key: "desc"),
	 * la categoria (key: "categoria"), la mitjana de les avaluacions dels comentaris (key: "avaluacio")
	 * i una llista dels tipus d' habitacio lliures (key: "habs") amb els seus noms
	 * (key: "tipusHab"), el nombre d'habitacions lliures (key: "numeroDisp") i el seu preu
	 * (key: "preu").
	 * @throws HotelsNoDisp 
	 * @throws PoblacioNoExisteix 
	 */
	Set<Map<String, Object> > buscarHabitacio(String pob, Date dIni, Date dFi, int numOcup) throws HotelsNoDisp, PoblacioNoExisteix {
		IFactoriaCtrlDades fCD = FactoriaCtrlDades.obteInstancia();
		ICtrlPoblacio cP = fCD.obteCtrlPoblacio();
		Poblacio p = cP.obte(pob);
		
		Set<Map<String,Object> > hotels = p.buscarHabitacio(dIni, dFi, numOcup);
		return hotels;
	}
}
